package com.hns.tool.export;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.StringReader;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.InvocationTargetException;
import java.math.BigDecimal;
import java.net.MalformedURLException;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.List;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.batik.transcoder.Transcoder;
import org.apache.batik.transcoder.TranscoderException;
import org.apache.batik.transcoder.TranscoderInput;
import org.apache.batik.transcoder.TranscoderOutput;
import org.apache.batik.transcoder.image.JPEGTranscoder;
import org.apache.batik.transcoder.image.PNGTranscoder;
import org.apache.commons.beanutils.PropertyUtils;
import org.apache.commons.io.FileUtils;
import org.apache.fop.svg.PDFTranscoder;

import com.hns.frame.enumrate.MsgType;
import com.hns.frame.exception.BusinessException;
import com.hns.tool.export.excel.excelNoTemplate.ExcelNoTemplate;
import com.hns.tool.export.excel.excelNoTemplate.ExportExcelNoTempEntity;
import com.hns.tool.export.excel.excelTemplate.ExcelTemplate;
import com.hns.tool.export.excel.excelTemplate.ExportExcelTempEntity;
import com.hns.tool.export.pdf.CellField;
import com.hns.tool.export.pdf.ExportPdfEntity;
import com.hns.tool.export.pdf.PdfContentTypeEnum;
import com.hns.tool.pub.ContextHolderUtils;
import com.hns.tool.pub.DataUtil;
import com.hns.tool.pub.PubUtil;
import com.hns.tool.pub.UtilString;
import com.itextpdf.text.BadElementException;
import com.itextpdf.text.Document;
import com.itextpdf.text.DocumentException;
import com.itextpdf.text.Element;
import com.itextpdf.text.Font;
import com.itextpdf.text.Image;
import com.itextpdf.text.PageSize;
import com.itextpdf.text.Paragraph;
import com.itextpdf.text.Phrase;
import com.itextpdf.text.pdf.BaseFont;
import com.itextpdf.text.pdf.PdfPTable;
import com.itextpdf.text.pdf.PdfPageEventHelper;
import com.itextpdf.text.pdf.PdfWriter;

/**
 * 导入导出工具类
 * @author:Fisher
 * @email:zhuangcaijin@126.com
 * @version Revision 2.0.0
 */
public class ExportUtil {
    
    /**
     * web根目录的本地路径
     */
    static String webRoot = null;
    
    /**
     * 导出页面chart图片
     * @param response
     * @throws Exception
     * @author:Fisher
     * @email:zhuangcaijin@126.com
     */
    public static void generatorChart(HttpServletResponse response) throws Exception {
        HttpServletRequest request = ContextHolderUtils.getRequest(); 
        String templateTempPath = getTemplateTempPath() + DataUtil.sequenceID();
        String type = request.getParameter("type");
        String svg = request.getParameter("svg");
        String filename = request.getParameter("filename");
        filename = filename == null ? "chart" : filename;
        String ext = generatorLocalChart(type, svg, templateTempPath);
        File tempFile = new File(templateTempPath);
        filename = filename + "." + ext;
        loadTmpFile(tempFile, filename, response);
    }
    
    /**
     * 将页面的chart保存到本地临时目录
     * @param type 类别
     * @param svg 
     * @param templateTempPath 页面chart保存目录
     * @return 图片类别字符串
     * @throws FileNotFoundException
     * @throws UnsupportedEncodingException
     * @throws IOException
     * @author:Fisher
     * @email:zhuangcaijin@126.com
     */
    public static String generatorLocalChart(String type, String svg, String templateTempPath) throws FileNotFoundException, UnsupportedEncodingException, IOException {
        File file = new File(templateTempPath);
        OutputStream out = new FileOutputStream(file); // 是否追加
        String ext = "";
        if (null != type && null != svg) {
            svg = svg.replaceAll(":rect", "rect");
            Transcoder t = null;
            if ("image/png".equals(type)) {
                ext = "png";
                t = new PNGTranscoder();
            } else if ("image/jpeg".equals(type)) {
                ext = "jpg";
                t = new JPEGTranscoder();
            } else if ("application/pdf".equals(type)) {
                ext = "pdf";
                t = (Transcoder) new PDFTranscoder();
            } else if ("image/svg+xml".equals(type)) {
                ext = "svg";
            }
            
            if (null != t) {
                TranscoderInput input = new TranscoderInput(new StringReader(svg));
                TranscoderOutput output = new TranscoderOutput(out);
                try {
                    t.transcode(input, output);
                } catch (TranscoderException e) {
                    // e.printStackTrace();
                }
            } else if ("svg".equals(ext)) {
                OutputStreamWriter writer = new OutputStreamWriter(out, "UTF-8");
                writer.append(svg);
                writer.close();
            } else {
                // nothing
            }
        }
        out.flush();
        out.close();
        return ext;
    }
    
    /**
     * 支持单一列表的导出
     * @param pdfEntity pdf设置实体
     * @param response
     * @throws Exception
     * @author:Fisher
     * @email:zhuangcaijin@126.com
     */
    public static void generatorPDF(ExportPdfEntity pdfEntity, HttpServletResponse response) throws Exception {
        // 模板临时文件目录--全局配置只用配置的第一个
        String templateTempPath = getTemplateTempPath() + DataUtil.sequenceID() + ".pdf";
        String showName = pdfEntity.getShowName();
        String pageSize = pdfEntity.getPageSize();
        PdfPageEventHelper pageEvent = pdfEntity.getPageEvent();
        // 输出流
        FileOutputStream out = new FileOutputStream(templateTempPath);
        // table实例
        PdfPTable dataTable;
        // 文档对象
        Document document = new Document(pageSize == null ? PageSize.A4 : PageSize.A4.rotate(), 50, 50, 100, 10);
        // pdf写入对象
        PdfWriter pdfWrite = PdfWriter.getInstance(document, out);
        // 分页事件
        pdfWrite.setPageEvent(pageEvent);
        document.open();
        
        dataTable = FillPdfTable(pdfEntity);
        document.add(dataTable);
        document.close();
        out.close();
        File tempFile = new File(templateTempPath);
        loadTmpFile(tempFile, showName + ".pdf", response);
    }
    
    /**
     * 支持多表单，多附件的导出
     * @param pdfEntityList pdf设置实体list
     * @param response
     * @throws Exception
     * @author:Fisher
     * @email:zhuangcaijin@126.com
     */
    public static void generatorPDF(List<ExportPdfEntity> pdfEntityList, HttpServletResponse response) throws Exception {
        
        if (PubUtil.isEmpty(pdfEntityList)) {
            throw new BusinessException(MsgType.WARN.getFlag(), "没有数据，请重新导出!");
        } else {
            // 模板临时文件目录--全局配置只用配置的第一个
            String templateTempPath = getTemplateTempPath() + DataUtil.sequenceID() + ".pdf";
            String showName = pdfEntityList.get(0).getShowName();
            String pageSize = pdfEntityList.get(0).getPageSize();
            // 输出流
            FileOutputStream out = new FileOutputStream(templateTempPath);
            // table实例
            PdfPTable dataTable;
            Image img;
            // 文档对象
            Document document = new Document(pageSize == null ? PageSize.A4 : PageSize.A4.rotate(), 50, 50, 100, 10);
            PdfPageEventHelper pageEvent = pdfEntityList.get(0).getPageEvent();
            // pdf写入对象
            PdfWriter pdfWrite = PdfWriter.getInstance(document, out);
            // 分页事件
            pdfWrite.setPageEvent(pageEvent);
            
            document.open();
            
            for (ExportPdfEntity entity : pdfEntityList) {
                Paragraph title = new Paragraph(entity.getTitle(), new Font(entity.getBaseFont()));
                document.add(title);
                if (entity.getContentType().equals(PdfContentTypeEnum.IMAGE.name())) {
                    img = FillPdfImage(entity.getImgPath());
                    document.add(img);
                } else if (entity.getContentType().equals(PdfContentTypeEnum.DATALIST.name())) {
                    dataTable = FillPdfTable(entity);
                    document.add(dataTable);
                }else if(entity.getContentType().equals(PdfContentTypeEnum.CUSTOM.name())){
                    dataTable = entity.getCustom();
                    document.add(dataTable);
                }
            }
            document.close();
            out.close();
            File tempFile = new File(templateTempPath);
            loadTmpFile(tempFile, showName + ".pdf", response);
        }
    }
    
    /**
     * 往PDF中填充的图片
     * @param imgPath 图片目录
     * @return img图片对象
     * @throws BadElementException
     * @throws MalformedURLException
     * @throws IOException
     * @author:Fisher
     * @email:zhuangcaijin@126.com
     */
    private static Image FillPdfImage(String imgPath) throws BadElementException, MalformedURLException, IOException {
        if (PubUtil.isEmpty(imgPath)) {
            throw new BusinessException(MsgType.WARN.getFlag(), "导出图片有误!");
        } else {
            Image img = Image.getInstance(imgPath);
            return img;
        }
    }
    
    /**
     * 填充pdf表格
     * @param pdfEntity pdf设置实体
     * @return pdf表格
     * @throws DocumentException
     * @throws IllegalAccessException
     * @throws InvocationTargetException
     * @throws NoSuchMethodException
     * @author:Fisher
     * @email:zhuangcaijin@126.com
     */
    private static PdfPTable FillPdfTable(ExportPdfEntity pdfEntity) throws DocumentException, IllegalAccessException, InvocationTargetException, NoSuchMethodException {
        BaseFont baseFont = pdfEntity.getBaseFont();
        // 表头字体格式
        Font headerFont = new Font(baseFont, 10, Font.BOLD);
        // 单元格字体格式
        Font content = new Font(baseFont, 9, Font.NORMAL);
        PdfPTable dataTable;
        // 如果存在自定义表头
        if (pdfEntity.getTableHeader() == null) {
            // 表格列数
            int NumColumns = pdfEntity.getNumColumns();
            dataTable = new PdfPTable(NumColumns);
            // 设置单元格宽度比例
            if (pdfEntity.getHeaderwidths() != null && pdfEntity.getHeaderwidths().length > 0) {
                dataTable.setWidths(pdfEntity.getHeaderwidths());
            }
            dataTable.setTotalWidth(pdfEntity.getPageSize() == null ? 527 : 774);// 设定总宽度
            dataTable.setLockedWidth(true);// 锁定宽度
            dataTable.setWidthPercentage(100);// 设置宽度百分比比例
            
            dataTable.getDefaultCell().setPadding(3);// 设置单元格内填充
            dataTable.getDefaultCell().setBorderWidth(0.3f);// 设置边框
            dataTable.getDefaultCell().setHorizontalAlignment(Element.ALIGN_CENTER); // 设置水平对齐方式
            
            // // 设置表头
            for (Object header : pdfEntity.getTableHeaderName()) {
                dataTable.addCell(new Paragraph(header.toString(), headerFont));
            }
            // 设置表头跟随
            dataTable.setHeaderRows(1);
            // 边框
            dataTable.getDefaultCell().setBorderWidth(0.1f);
            if (PubUtil.isNotEmpty(pdfEntity.getTableContent())) {
                // 添加表格内容
                for (Object item : pdfEntity.getTableContent()) {
                    for (int i = 0, size = pdfEntity.getTableField().size(); i < size; i++) {
                        // 带格式的单元格
                        CellField cell = pdfEntity.getTableField().get(i);
                        dataTable.getDefaultCell().setHorizontalAlignment(cell.getAlign());
                        Object property = PropertyUtils.getProperty(item, cell.getFieldName());
                        String pro;// = property == null ? "" :
                                   // property.toString();
                        if (property == null) {
                            pro = "";
                        } else if (property instanceof BigDecimal) {
                            DecimalFormat df = new DecimalFormat("#,###.00");
                            pro = df.format(property);
                            pro = pro.equals(".00") ? "0" : pro;
                        } else {
                            pro = property.toString();
                        }
                        dataTable.addCell(new Phrase(pro, content));
                    }
                }
            } else {
                throw new BusinessException(MsgType.WARN.getFlag(), "没有数据，请重新选择导出!");
            }
        } else {
            throw new BusinessException(MsgType.WARN.getFlag(), "表头不允许为控制!");
        }
        
        return dataTable;
    }
    
    /**
     * 根据excel模板导出对应excel表格
     * @param exportEntity 导出实体类
     * @param response
     * @author:Fisher
     * @email:zhuangcaijin@126.com
     */
    public static void generatorExcelByTemplate(ExportExcelTempEntity exportEntity, HttpServletResponse response) {
        String path = getWebRoot();
        String templatePath = path + "/template/";
        String targetPath = path + "/template/temp/" + UtilString.getUUID() + ".xls";
        ExcelTemplate etemp = new ExcelTemplate(templatePath + exportEntity.getTempName(), targetPath);
        try {
            etemp.generate(exportEntity.getDataSource(), exportEntity.getTitle());
            File tempFile = new File(targetPath);
            loadFile(tempFile, exportEntity.getShowName() + ".xls", response);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    
    /**
     * 无模板导出excel表格
     * @param exportEntity 导出实体类
     * @param response
     * @author:Fisher
     * @email:zhuangcaijin@126.com
     */
    public static void generatorExcelNoTemplate(ExportExcelNoTempEntity exportEntity, HttpServletResponse response) {
        String path = getWebRoot();
        String targetPath = path + "/template/temp/" + UtilString.getUUID() + ".xls";
        ExcelNoTemplate eNotemp = new ExcelNoTemplate(targetPath);
        try {
            eNotemp.generate(exportEntity);
            File tempFile = new File(targetPath);
            loadFile(tempFile, exportEntity.getShowName() + ".xls", response);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    
    /**
     * 得到路径
     * @return 路径字符串
     * @author:Fisher
     * @email:zhuangcaijin@126.com
     */
    public static String getPath() {
        String path = getWebRoot();
        String targetPath = path + "/template/temp/" + UtilString.getUUID() + ".xls";
        return targetPath;
    }
    
    /**
     * 生成并下载文件
     * @param targetPath 文件路径
     * @param showName 文件名
     * @param response
     * @author:Fisher
     * @email:zhuangcaijin@126.com
     */
    public static void GeneratorLoadFile(String targetPath, String showName, HttpServletResponse response) {
        try {
            File tempFile = new File(targetPath);
            loadFile(tempFile, new String(showName.getBytes("gbk"), "ISO8859-1") + ".xls", response);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    
    /**
     * 生成并下载文件
     * @param targetPath 文件路径
     * @param showName 文件名
     * @param fileType 扩展名
     * @param response
     * @author:Chenl
     * @email:370238764@qq.com
     */
    public static void GeneratoDownFile(String targetPath, String showName,String fileType ,HttpServletResponse response) {
        try {
            File tempFile = new File(targetPath);
            loadFile(tempFile, new String(showName.getBytes("gbk"), "ISO8859-1") + fileType, response);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    
    /**
     * 下载文件并删除临文件
     * @param temp 文件
     * @param showName 文件名
     * @param response
     * @throws IOException
     * @author:Fisher
     * @email:zhuangcaijin@126.com
     */
    public static void loadTmpFile(File temp, String showName, HttpServletResponse response) throws IOException {
        OutputStream os = response.getOutputStream();
        try {
            response.reset();
            response.setHeader("Content-Disposition", "attachment; filename=" + new String(showName.getBytes("gbk"), "ISO8859-1"));
            response.setContentType("application/octet-stream; charset=utf-8");
            os.write(FileUtils.readFileToByteArray(temp));
            os.flush();
        } finally {
            if (os != null) {
                os.close();
                temp.delete();
            }
        }
    }
    
    /**
     * 下载文件
     * @param temp 文件
     * @param showName 文件名
     * @param response
     * @throws IOException
     * @author:Fisher
     * @email:zhuangcaijin@126.com
     */
    public static void loadFile(File temp, String showName, HttpServletResponse response) throws IOException {
        OutputStream os = response.getOutputStream();
        try {
            response.reset();
            response.setHeader("Content-Disposition", "attachment; filename=" + showName);
            response.setContentType("application/octet-stream; charset=utf-8");
            os.write(FileUtils.readFileToByteArray(temp));
            os.flush();
        } finally {
            if (os != null) {
                os.close();
            }
        }
    }
    
    /**
     * 获取web根目录路径
     * @param request
     * @return 路径字符串
     * @author:Fisher
     * @email:zhuangcaijin@126.com
     */
    public static String getWebRoot() {
        HttpServletRequest request = ContextHolderUtils.getRequest();
        if (webRoot == null) {
            webRoot = request.getSession().getServletContext().getRealPath("/");
        }
        return webRoot;
    }
    
    /**
     * 获取模版文件的路径
     * @param request
     * @return 路径字符串
     * @author:Fisher
     * @email:zhuangcaijin@126.com
     */
    public static String getTemplatePath() {
        return getWebRoot() + "/template/";
    }
    
    /**
     * 获取临时文件目录
     * @param request
     * @return 目录字符串
     * @author:Fisher
     * @email:zhuangcaijin@126.com
     */
    public static String getTemplateTempPath() {
        return getWebRoot() + "/template/temp/";
    }
    
    /**
     * 导出文件
     * @param tableHeaderNames 导出表头名称
     * @param tableHeaderFields 导出字段名
     * @param list 导出数据
     * @param response
     * @param type 导出文件类型
     * @param showName 导出文件表头
     * @param title 导出文件字段名
     * @throws Exception
     * @author:zhangyu
     * @email:zhangyu2222z@sina.cn
     */
    public static void exportFiles(List<String> tableHeaderNames, List<String> tableHeaderFields, List list,
    		HttpServletResponse response, String type, String showName, String title) throws Exception {
        if(type.equals("excel")){//excel
        	List<String> headerNames = tableHeaderNames;
            List<String> headerFields = tableHeaderFields;
//            List<Map<String, Object>> maplist = PubUtil.convertObjectToListMap(list);
            ExportExcelNoTempEntity exportEntity = new ExportExcelNoTempEntity(headerNames,headerFields,list);
            exportEntity.setShowName(showName);
            exportEntity.setTitle(title);
            generatorExcelNoTemplate(exportEntity, response);
        }else if(type.equals("pdf")){//pdf
        	ExportPdfEntity pdfEntity = new ExportPdfEntity();
            pdfEntity.setPageSize("100");
            pdfEntity.setTableContent(list);
            pdfEntity.setShowName(showName);
            pdfEntity.setTitle(title);
            pdfEntity.setTableHeaderName(tableHeaderNames);
            List<CellField> tableField = new ArrayList<CellField>();
            for(int i=0;i<tableHeaderFields.size(); i++){
            	CellField cell = new CellField();
            	cell.setFieldName(tableHeaderFields.get(i));
            	tableField.add(cell);
            }
            pdfEntity.setTableField(tableField);
            generatorPDF(pdfEntity,  response);
        }else{
        	throw new BusinessException(MsgType.WARN.getFlag(), "无法导出对应格式文件！");
        }
    }
    
}
